package contegor.scire.core.queries;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import contegor.scire.core.Connectable;
import contegor.scire.core.Container;
import contegor.scire.core.Id;
import contegor.scire.core.Task;
import contegor.scire.core.TaskId;
import contegor.scire.core.Version;
import contegor.scire.core.WithDependencies;

/**
 * Base {@link Query} for all the ones that depends on others.
 *
 * @version $Revision: 1.2 $
 * @author  Héctor Cirbián Pousa ($Author: hector $)
 */
@Version("$Id: QueryWithDependencies.java,v 1.2 2010-02-01 10:55:42 hector Exp $")
public abstract class QueryWithDependencies<I extends Connectable, O extends Connectable> extends Query<O> implements WithDependencies<I, O> {
  private static final long serialVersionUID = -9160158641749988020L;

  protected List<Query<I>> dependencies;

  /**
   * Constructor for {@link Query} with only one dependency. The target container where <code>this</code>
   * will be processed will be the same that the one of the dependency.
   * 
   * @param dependency {@link Query} in which depends this one.
   */
  @SuppressWarnings("unchecked")
  public QueryWithDependencies(Query<I> dependency) {
    super(dependency.getTargetContainerId());
    this.dependencies = Collections.unmodifiableList(Arrays.asList(dependency));
  }

  /**
   * Constructor for {@link Query} with only one dependency. The target container where <code>this</code>
   * will be processed will be the same that the one of the dependency.
   * <b>Internal use only.</b>
   * 
   * @param taskId {@link TaskId} of the {@link Query}.
   * @param dependency {@link Query} in which depends this one.
   */
  @SuppressWarnings("unchecked")
  protected QueryWithDependencies(TaskId taskId, Query<I> dependency) {
    super(taskId, dependency.getTargetContainerId());
    this.dependencies = Collections.unmodifiableList(Arrays.asList(dependency));
  }

  /**
   * Constructor for {@link Query} with more than one dependency.
   * 
   * @param targetContainerId {@link Id} of the {@link Container} where this {@link Query} will be processed.
   * @param dependency {@link Query} in which depends this one.
   */
  public QueryWithDependencies(Id targetContainerId, Query<I> ... dependencies) {
    super(targetContainerId);
    if (dependencies != null)
      this.dependencies = Collections.unmodifiableList(Arrays.asList(dependencies));
    else
      this.dependencies = Collections.emptyList();
  }
  
  /**
   * Constructor for {@link Query} with more than one dependency.
   * <b>Internal use only.</b>
   * 
   * @param taskId {@link TaskId} of the {@link Query}.
   * @param targetContainerId {@link Id} of the {@link Container} where this {@link Query} will be processed.
   * @param dependency {@link Query} in which depends this one.
   */
  protected QueryWithDependencies(TaskId taskId, Id targetContainerId, Query<I> ... dependencies) {
    super(taskId, targetContainerId);
    if (dependencies != null)
      this.dependencies = Collections.unmodifiableList(Arrays.asList(dependencies));
    else
      this.dependencies = Collections.emptyList();
  }

  @Override
  public List<? extends Task<I>> getDependencies() {
    return this.dependencies;
  }

  @Override
  public void setTaskId(TaskId taskId) {
    super.setTaskId(taskId);
    for (Query<I> dependencie: dependencies)
      dependencie.setTaskId(taskId.next(true));
  }
}
